﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Zombie_Demo.World.NPC
{
     public class AI
     {
          protected bool wander = false;
          protected Vector2 anchor;
          protected Vector2 position;
          protected int leashRange, steps;
          protected float speed;
          protected float rotation, spriteRot;
          protected StepType step = StepType.Direction;
          protected enum StepType { Direction, Time, Move, Rest };
          protected Vector2 destination;
          protected TimeSpan restTime;
          protected int heading = 1; //1 for right, -1 for left

          protected StepType CurrentStep { get { return this.step; } }
          virtual public float Rotation { get { return this.rotation; } }
          public float SpriteRot { get { return this.spriteRot; } }
          virtual public Vector2 Position { get { return this.position; } }
          protected Vector2 Destination { get { return this.destination; } }

          public AI()
          {
               this.anchor = Vector2.Zero;
               this.position = Vector2.Zero;
               this.wander = true;
               leashRange = 100;
               speed = 1;
               rotation = 0.0f;
          }

          public AI(Vector2 anchor)
          {
               this.anchor = anchor;
               this.position = anchor;
               this.wander = true;
               leashRange = 100;
               speed = 5;
               rotation = 0.0f;
          }

          public AI(Vector2 anchor, Vector2 position)
          {
               this.anchor = anchor;
               this.position = position;
               this.wander = true;
               leashRange = 100;
               speed = 5;
               rotation = 0.0f;
          }

          public AI(Vector2 anchor, bool wander)
          {
               this.anchor = anchor;
               this.position = anchor;
               this.wander = wander;
               leashRange = 100;
               speed = 5;
               rotation = 0.0f;
          }

          public AI(Vector2 anchor, bool wander, int leash)
          {
               this.anchor = anchor;
               this.position = anchor;
               this.wander = wander;
               leashRange = leash;
               speed = 1;
               rotation = 0.0f;
          }

          public void Update(GameTime gameTime)
          {
               //rotation = rotation % 360;
               if (Utilities.Maths.Distance(anchor, position) > leashRange)
               {
                    this.destination = this.anchor;
                    StepToAnchor();
                    step = StepType.Move;
               }
               switch (step)
               {
                    case StepType.Direction:
                         GetRandDirection();
                         step = StepType.Time;
                         break;
                    case StepType.Move:
                         if (this.steps != 0)
                              Step();
                         else
                         {
                              step = StepType.Rest;
                              RestTime();
                         }
                         break;
                    case StepType.Rest:
                         restTime = restTime.Subtract(gameTime.ElapsedGameTime);
                         if (restTime <= TimeSpan.Zero)
                              step = StepType.Direction;
                         break;
                    case StepType.Time:
                         LengthOfMove();
                         step = StepType.Move;
                         SetDest();
                         SetSpriteRot();
                         break;
               }
          }

          private void StepToAnchor()
          {
               Vector2 distance = anchor - position;
               rotation = MathHelper.ToDegrees((float)Math.Atan2(distance.Y, distance.X));
               LengthOfMove();
          }

          private void Step()
          {
               float x = (float)Math.Cos(MathHelper.ToRadians(rotation));
               float y = (float)Math.Sin(MathHelper.ToRadians(rotation));
               position.X += (x * speed);
               position.Y += (y * speed);

               if (x > 0)
               {
                    this.heading = 1;
               }
               else
               {
                    this.heading = -1;
               }
               steps--;
          }

          private void RestTime()
          {
               restTime = new TimeSpan(0, 0, 0, Utilities.Maths.RandomInt(10));
          }

          private void LengthOfMove()
          {
               int maxDist = (int)(leashRange / speed);
               steps = Utilities.Maths.RandomInt(maxDist);

               if (steps == 0)
                    steps = Utilities.Maths.RandomInt(leashRange);
          }

          private void GetRandDirection()
          {
               int newRot = Utilities.Maths.RandomInt(360);
               rotation = newRot;
          }

          private void SetDest()
          {
               this.destination = Vector2.Zero;
               float x = (float)Math.Cos(MathHelper.ToRadians(rotation + 270));
               float y = (float)Math.Sin(MathHelper.ToRadians(rotation + 270));
               destination.X += ((x * speed * steps) + this.position.X);
               destination.Y += ((y * speed * steps) + this.position.Y);
          }

          private void SetSpriteRot()
          {
               Vector2 distance = Vector2.Zero;
               distance.X = this.destination.X - this.position.X;
               distance.Y = this.destination.Y - this.position.Y;
               this.spriteRot = (float)Math.Atan2(distance.Y, distance.X);
          }
     }
}
